View的层级
在Interface Builder中,约在下面的View层级约高
如下图
TestView2就显示在TestView1之上
在使用代码动态添加View时,Cocoa并不能为我们保证View的层级,比如我往TestView1里面添加一个subview,TestView2可能就显示在TestView1之上了。
这时候我们需要通过代码来手动排版一下。
如下
[self.testview2 removeFromSuperview];
[self.rootView addSubview:self.testview2 positioned:NSWindowAbove relativeTo:nil];
鼠标事件的派发与处理
查找需要派发鼠标事件的View
事件最开始由当前 NSWindow 的 sendEvent:
方法发送出去
通过NSView的- (nullable NSView *)hitTest:(NSPoint)point
方法,找到接收鼠标事件的View。
hitTest的调用过程是按照View显示的层级,从最外层的View开始,然后依次往下调用。最后会找到最深的并且显示在最前面的那个View。
父View的hitTest调用子类的hitTest来层层寻找。默认的,最后的子类在响应的point找不到更小的子类了就会返回自己。
View处理鼠标事件
找到需要派发的NSView后,就会发送响应的方法,比如- (void)mouseDown:(NSEvent *)event
、- (void)mouseDragged:(NSEvent *)event
等
通过自定义的View继承自NSView,重载这些方法,我们可以处理鼠标的事件。
继续派发
这里需要注意的是,在时间处理方法中,比如- (void)mouseDown:(NSEvent *)
中,如果调用了[super mouseDown:event];
事件会继续派发下去
hitTest会继续执行,往下寻找下一个需要派发事件的View
其他
- 对于透明的窗口,上面放一个透明的View,鼠标的事件是不会派发到这个View上面的,这时候需要对window设置一下:
[window setIgnoresMouseEvents:NO]
,参见